﻿using System;
using GodProject.peoples;

namespace GodProject.console
{
  /// <summary>
  /// Provides set of methods for printing various info and messages on console
  /// with custom color and format
  /// </summary>
  class GodConsoleWriter
  {
    /// <summary>
    /// Provides color scheme, used by console
    /// </summary>
    private readonly ColorScheme _scheme;
    /// <summary>
    /// Console's width
    /// </summary>
    private const int BufferWidth = Int16.MaxValue / 2;
    /// <summary>
    /// Console's height
    /// </summary>
    private const int BufferHeight = Int16.MaxValue / 2;

    /// <summary>
    /// Constructor.
    /// </summary>
    /// <param name="scheme">color scheme for console</param>
    internal GodConsoleWriter(ColorScheme scheme)
    {
      _scheme = scheme;
      Console.SetBufferSize(BufferWidth, BufferHeight);
    }

    #region "Simple messages printing"
    /// <summary>
    /// Prints messages about internal error
    /// </summary>
    private void PrintInternalError()
    {
      Console.BackgroundColor = _scheme.ErrorBackground;
      Console.ForegroundColor = _scheme.ErrorForeground;
      Console.WriteLine(Messages.InternalError);
      Console.ResetColor();
    }

    /// <summary>
    /// Prints user prompt
    /// </summary>
    internal void WritePrompt()
    {
      Console.WriteLine();
      Console.WriteLine(Messages.Prompt);
    }

    /// <summary>
    /// Prints message about creation start
    /// </summary>
    internal void WriteStartCreation()
    {
      Console.WriteLine(Messages.Start);
    }

    /// <summary>
    /// Prints lines for reserving place for human's pair
    /// </summary>
    internal void WriteReservedLinesForFuturePair()
    {
      Console.WriteLine(Messages.NonPairLinesDelimiter, Environment.NewLine);
    }
    #endregion "Simple messages printing"



    #region "Human info printing"
    /// <summary>
    /// Prints info about pair human (created secondly) on console
    /// </summary>
    /// <param name="human">human to be printed</param>
    /// <param name="left">left coorfinate for start position on console</param>
    /// <param name="top">top coordinate for start position on console</param>
    internal void WritePairHumanToConsole(Human human, int left, int top)
    {
      Console.CursorTop = top;
      Console.CursorLeft = left;
      WriteToConsole(human, _scheme.PairBackground);
    }

    /// <summary>
    /// Write non-pair (firstly created) human on console
    /// </summary>
    /// <param name="human">human to be printed on console</param>
    internal void WriteNonPairToConsole(Human human)
    {
      WriteToConsole(human, _scheme.NonPairBackground);
    }

    /// <summary>
    /// Writes human's info on console
    /// </summary>
    /// <param name="human">human to be printed</param>
    /// <param name="backgroundColor">info's background color</param>
    private void WriteToConsole(Human human, ConsoleColor backgroundColor)
    {
      if (human is Botan)
      {
        Botan botan = human as Botan;
        WriteHumanInfo(botan, backgroundColor);
      }
      else if (human is Student)
      {
        Student student = human as Student;
        WriteHumanInfo(student, backgroundColor);
      }
      else if (human is CoolParent)
      {
        CoolParent coolParent = human as CoolParent;
        WriteHumanInfo(coolParent, backgroundColor);
      }
      else if (human is Parent)
      {
        Parent parent = human as Parent;
        WriteHumanInfo(parent, backgroundColor);
      }
    }

    /// <summary>
    /// Prints info about Parent on console
    /// </summary>
    /// <param name="parent">parent to be writed on console</param>
    /// <param name="backgroundColor">background color</param>
    private void WriteHumanInfo(Parent parent, ConsoleColor backgroundColor)
    {
      if (parent == null)
      {
        PrintInternalError();
        return;
      }
      string sexDescription = GetSexDescription(parent.Sex);
      Console.ForegroundColor = _scheme.ParentForeground;
      Console.BackgroundColor = backgroundColor;
      String parentDescription = String.Format(Messages.DescriptionParent, parent.Name, sexDescription, parent.Age,
                                               parent.ChildCount);
      Console.Write(parentDescription);
    }

    /// <summary>
    /// Prints info about Cool Parent on console
    /// </summary>
    /// <param name="coolParent">Cool parent to be writed on console</param>
    /// <param name="backgroundColor">background color</param>
    private void WriteHumanInfo(CoolParent coolParent, ConsoleColor backgroundColor)
    {
      if (coolParent == null)
      {
        PrintInternalError();
        return;
      }
      WriteCoolParentWithoutMoney(coolParent, backgroundColor);
      WriteCoolParentMoney(coolParent);
      WriteCoolParentEnd(backgroundColor);
    }

    /// <summary>
    /// Prints end of info about cool parent
    /// </summary>
    /// <param name="backgroundColor">background color of infi</param>
    private void WriteCoolParentEnd(ConsoleColor backgroundColor)
    {
      Console.ForegroundColor = _scheme.CoolParentForeground;
      Console.BackgroundColor = backgroundColor;
      Console.Write(Messages.DescriptionCoolParentEnd);
      Console.ResetColor();
    }

    /// <summary>
    /// Prints info about cool parent's money count
    /// </summary>
    /// <param name="coolParent">cool parent, which info will be printed</param>
    private void WriteCoolParentMoney(CoolParent coolParent)
    {
      Console.ForegroundColor = _scheme.CoolParentForeground;
      Console.BackgroundColor = _scheme.CoolParentMoneyBackground;
      String descriptionCoolParentsMoney = String.Format(Messages.DescriptionCoolParentsMoney, coolParent.Money);
      Console.Write(descriptionCoolParentsMoney);
      Console.ResetColor();
    }

    /// <summary>
    /// Prints info (except money) about cool parent on console
    /// </summary>
    /// <param name="coolParent">cool parent, which info will be printed</param>
    /// <param name="backgroundColor">background color for info</param>
    private void WriteCoolParentWithoutMoney(CoolParent coolParent, ConsoleColor backgroundColor)
    {
      Console.ForegroundColor = _scheme.CoolParentForeground;
      Console.BackgroundColor = backgroundColor;
      string sexDescription = GetSexDescription(coolParent.Sex);
      String descriptionCoolParentWithoutMoney = String.Format(Messages.DescriptionCoolParentWithoutMoney,
                                                               coolParent.Name, sexDescription, coolParent.Age,
                                                               coolParent.ChildCount);
      Console.Write(descriptionCoolParentWithoutMoney);
      Console.ResetColor();
    }

    /// <summary>
    /// Prints info about Student on console
    /// </summary>
    /// <param name="student">Student to be writed on console</param>
    /// <param name="backgroundColor">background color for info</param>
    private void WriteHumanInfo(Student student, ConsoleColor backgroundColor)
    {
      if (student == null)
      {
        PrintInternalError();
        return;
      }
      string sexDescription = GetSexDescription(student.Sex);
      Console.ForegroundColor = _scheme.StudentForeground;
      Console.BackgroundColor = backgroundColor;
      String studentDescription = String.Format(Messages.DescriptionStudent, student.Name, student.Middlename,
                                                sexDescription, student.Age);
      Console.Write(studentDescription);
    }

    /// <summary>
    /// Prints info about Botan on console
    /// </summary>
    /// <param name="botan">Botan to be writed on console</param>
    /// <param name="backgroundColor">background color for info</param>
    private void WriteHumanInfo(Botan botan, ConsoleColor backgroundColor)
    {
      if (botan == null)
      {
        PrintInternalError();
        return;
      }
      string sexDescription = GetSexDescription(botan.Sex);
      Console.ForegroundColor = _scheme.BotanForeground;
      Console.BackgroundColor = backgroundColor;
      String botanDesciption = String.Format(Messages.DescriptionBotan, botan.Name, botan.Middlename, sexDescription,
                                             botan.Age, botan.AverageMark);
      Console.Write(botanDesciption);
    }

    /// <summary>
    /// Returns sex text description
    /// </summary>
    /// <param name="sex">sex</param>
    /// <returns>sex's text description</returns>
    private string GetSexDescription(Sex sex)
    {
      return sex == Sex.Male ? Messages.SexMale : Messages.SexFemale;
    }

    #endregion "Human info printing"

  }
}
